iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0
JavaScript

JS 核心重構:勇者轉職傳說系列 第 28

Day 27:【戰略指揮】資料驅動 (State-driven):從動手肌肉,到下達腦袋指令

  • 分享至 

  • xImage
  •  

本文同步分享於個人部落格:Liwen Chiou | Digital Architect & Full-Stack Engineer


📜 這裡的修煉規則:

「導師,我不想再手動改 HTML 了,真的好累。」

聽著,孩子。當你的小隊只有 3 個人時,你確實可以一個一個拍肩膀下令。但當你指揮的是萬人大軍,你需要的不是體力,而是 「戰略系統」

今天,我們不學新語法。我們要學習如何 「換一顆腦袋」。這是你這 30 天修煉中最痛苦的一天,卻也是你脫胎換骨的一天。


🛡️ 【公會大廳:導師的修煉導讀】

「導師,Day 18 的待辦清單專案,我加了一個『編輯功能』後,程式碼就炸開了...」

我看著那疊厚厚的代碼,裡面充滿了 document.getElementByIdappendChildinnerHTML = ""。每一行邏輯都像藤蔓一樣死死地纏繞在 HTML 標籤上。

「孩子,你這是在 『手動控制每一條肌肉』。每當你想讓勇者揮劍,你都要手動計算肌肉的收縮、骨骼的移動。難怪你累壞了。」

「那我們該怎麼辦?」

「很簡單。你只需要告訴勇者:『目標:史萊姆,動作:揮劍』。至於怎麼收縮肌肉,那是 『自動化生產線』 的事。這,就是 資料驅動 (State-driven)。」


💡 【導師講義:底層真相探究】

在現代開發中,我們將網頁拆解為兩個部分:大腦 (State)投影機 (Render)

1. 什麼是 State (狀態)?

它是你應用程式唯一的真相來源。它通常是一個簡單的 JS 物件或陣列。

  • 範例const monsterList = [{ name: '史萊姆', hp: 100 }];
  • 原則:大腦只管資料長什麼樣子,完全不理會網頁上有沒有 <div>

2. 什麼是 Render (渲染)?

它是一台盲目的投影機。它的工作只有一個:讀取大腦的資料,然後噴出對應的 HTML。

  • 原則:渲染函式不具備思考能力,你給它什麼資料,它就畫出什麼畫面。

3. 核心心法:單向驅動

當你想改變畫面時,絕對禁止 直接去動 DOM。

  1. 修改資料 (State):例如將 HP 從 100 改成 80。
  2. 重新投影 (Render):呼叫渲染函式,它會根據新資料重新畫一遍。

🏹 導師的辨析圖:手動操控 vs 資料驅動

特性 手動操控 (DOM-driven) 資料驅動 (State-driven)
修改對象 直接改 HTML 標籤 只改 JS 物件資料
程式碼長相 充滿 querySelector 充滿 Array 方法 (map/filter)
維護難度 極高 (改 A 壞 B) 低 (資料清純,畫面好修)

導師的圖解心法: 整個流程就像是一場電影放映。你的 State 就是「底片」,Render 函式就是「投影機」。如果你想改變螢幕上的內容,你該做的是換一張底片,而不是跑去螢幕前面塗鴉。

資料驅動流程圖


⚔️ 【戰術對抗:學長與學弟的代碼對決】

招式示範:更新血量顯示

❌ 冒險學弟:肌肉勞損法

// 如果血量變了,我要手動抓標籤,然後改顏色,改文字...
function takeDamage(id, amount) {
  const hpEl = document.querySelector(`#hp-${id}`);
  const newHp = Number(hpEl.textContent) - amount;
  hpEl.textContent = newHp;
  if (newHp < 20) hpEl.style.color = "red";
}
  • 負能量評級:🔴 邏輯與樣式死結 / 🔴 難以擴展

✅ 勇者學長:指揮官心法

// 1. 大腦 (State)
let monsterState = { hp: 100, name: "史萊姆" };

// 2. 投影機 (Render)
function render() {
  const container = document.getElementById("app");
  // 💡 直接用資料決定畫面內容與樣式
  container.innerHTML = `
    <div class="monster" style="color: ${monsterState.hp < 20 ? "red" : "black"}">
      ${monsterState.name} - HP: ${monsterState.hp}
    </div>
  `;
}

// 3. 修改資料 (State)
function takeDamage(amount) {
  monsterState.hp -= amount; // 只改資料
  render(); // 重新投影
}
  • 利潤評級:🟢 邏輯集中 / 🟢 畫面完全由資料決定

導師講評: 注意看學長的寫法。render 函式完全不知道「血量為什麼會變」,它只知道「現在資料是多少,我就畫什麼」。這就是我們在 Day 25 學過的 SoC (關注點分離) 的極致表現。


🏰 【勇者精英課:邁向職人的進階架構】

你可能會問:「導師,每次資料變了都要重新 innerHTML 整塊畫面,效能不會很差嗎?」

好問題!這就是為什麼我們需要這 30 天修煉的終點 —— 現代前端框架。它們在底層實作了複雜的「差分算法 (Diffing)」,能聰明地只更新有變動的小地方。

但在你拿起聖劍前,你必須先學會「不直接動 DOM」的思維。因為如果你還抱持著「手動抓 ID 改文字」的習慣,那你就永遠無法發揮聖劍的威力。


🛖 【營火叮嚀:導師的經驗談】

我曾經在一個大型專案中,因為懶得寫 Render 函式,直接在一個 Ajax 的回呼裡改了 5 個 DOM。結果過了三個月,另一個功能也需要改那 5 個 DOM。

到了最後,我的程式碼裡有 20 個地方在競爭那 5 個 DOM 的主控權。那是我的工程生涯中,離「崩潰」最近的一次。

從那天起,我發誓:除非是極簡單的特效,否則我絕對不再直接操作 DOM。我只改資料。


天色微亮,營火雖已燃盡,但你眼中卻閃爍著領悟的光芒。在前往演武場挑戰關卡前,我已經幫你把靈魂碎片精煉成了這份「戰術錦囊」。拿好它,今日的任務不再是負擔,而是你證明自我的舞台。去吧,公會的英雄榜在等著你的戰報。

📝 【夥伴筆記:今日修煉精華】

  • State (狀態):應用的靈魂,唯一的真相。
  • Render (渲染):將 State 具現化為 HTML 的純函式。
  • 黃金法則資料驅動 UI (UI = f(state))。資料一變,畫面必變。

🎯 【實戰演武場】

⚔️ 任務鑑定條件:

  1. 完成 📜 本日實戰任務 (CodePen)
  2. 將 CodePen 網址貼至 QuestBoard,並回填鑑定報告:
    • 初心者:指揮官啟蒙 (成就感發掘)
        1. 你能成功透過修改 state 陣列,讓畫面自動多出一隻史萊姆嗎?
    • 冒險者:戰略大師 (理性挑戰)[⚡ 觀念辨析]
        1. 為什麼說「資料驅動」比起「手動操作 DOM」更適合團隊協作?

📚 【圖書館卷軸:延伸學習】


上一篇
Day 26:【效能神兵】防抖 (Debounce) 與節流 (Throttle) 的冷卻機制
下一篇
Day 28:【封印揭曉】萬物回歸!原來你這 30 天練的基礎,合起來就是「那柄聖劍」
系列文
JS 核心重構:勇者轉職傳說31
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言